home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / actionrp / nhplusx.bin / nhplusx / nhplusX / X11 / winmenu.c < prev    next >
C/C++ Source or Header  |  1995-09-10  |  10KB  |  422 lines

  1. /*    SCCS Id: @(#)winmenu.c    3.1    93/02/04    */
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * File for creating menus.
  7.  * 
  8.  *     + Global functions: start_menu, add_menu, end_menu, select_menu
  9.  */
  10.  
  11. #ifndef SYSV
  12. #define PRESERVE_NO_SYSV    /* X11 include files may define SYSV */
  13. #endif
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/StringDefs.h>
  17. #include <X11/Shell.h>
  18. #include <X11/Xaw/List.h>
  19. #include <X11/Xaw/Viewport.h>
  20. #include <X11/Xaw/Cardinals.h>
  21. #include <X11/Xatom.h>
  22.  
  23. #ifdef PRESERVE_NO_SYSV
  24. # ifdef SYSV
  25. #  undef SYSV
  26. # endif
  27. # undef PRESERVE_NO_SYSV
  28. #endif
  29.  
  30. #include "hack.h"
  31. #include "winX.h"
  32.  
  33.  
  34. static void FDECL(menu_select, (Widget,XtPointer,XtPointer));
  35. static void FDECL(clear_old_menu, (struct xwindow *));
  36. static char *FDECL(copy_of, (const char *));
  37.  
  38.  
  39. static char menu_selected;    /* selected menu item */
  40. static const char menu_translations[] =
  41.     "#override\n\
  42.      <Key>: menu_key()";
  43.  
  44. /*
  45.  * Menu callback.
  46.  */
  47. /* ARGSUSED */
  48. static void
  49. menu_select(w, client_data, call_data)
  50.     Widget w;
  51.     XtPointer client_data, call_data;
  52. {
  53.     XawListReturnStruct *lrs = (XawListReturnStruct *) call_data;
  54.     int i;
  55.     struct menu_info_t *menu_info;
  56.     struct menu_item *curr;
  57.     struct xwindow *wp;
  58.  
  59.     wp = find_widget(w);
  60.     menu_info  = wp->menu_information;
  61.  
  62.     for (i = 0, curr = menu_info->base; i < lrs->list_index; i++) {
  63.     if (!curr) panic("menu_select: out of menu items!");
  64.     curr = curr->next;
  65.     }
  66.  
  67.     /* If we don't have a selector, try again. */
  68.     if (!curr->selector) {
  69.     XawListUnhighlight(w);    /* unhilight non-menu item */
  70.     X11_nhbell();
  71.     return;
  72.     }
  73.     menu_selected = curr->selector;
  74.  
  75.     nh_XtPopdown(wp->popup);    /* this removes the event grab */
  76.     exit_x_event = TRUE;    /* exit our event handler */
  77. }
  78.  
  79. /*
  80.  * Called when menu window is deleted.
  81.  */
  82. /* ARGSUSED */
  83. void
  84. menu_delete(w, event, params, num_params)
  85.     Widget w;
  86.     XEvent *event;
  87.     String *params;
  88.     Cardinal *num_params;
  89. {
  90.     menu_selected = '\033';
  91.     nh_XtPopdown(w);        /* this removes the event grab */
  92.     exit_x_event = TRUE;    /* exit our event handler */
  93. }
  94.  
  95. /*
  96.  * Called when we get a key press event on a menu window.
  97.  */
  98. /* ARGSUSED */
  99. void
  100. menu_key(w, event, params, num_params)
  101.     Widget w;
  102.     XEvent *event;
  103.     String *params;
  104.     Cardinal *num_params;
  105. {
  106.     struct menu_info_t *menu_info;
  107.     struct menu_item *curr;
  108.     struct xwindow *wp;
  109.     char ch;
  110.     int count;
  111.  
  112.     wp = find_widget(w);
  113.     menu_info  = wp->menu_information;
  114.  
  115.     ch = key_event_to_char((XKeyEvent *) event);
  116.  
  117.     if (ch == '\0') {    /* don't accept nul char/modifier event */
  118.     /* don't beep */
  119.     return;
  120.     }
  121.  
  122.     for (count = 0, curr = menu_info->base; curr; curr = curr->next, count++)
  123.     if (curr->selector == ch) break;
  124.  
  125.     if (curr) {
  126.     XawListHighlight(w, count);    /* highlit item */
  127.     menu_selected = ch;
  128.     } else if (menu_info->other_valid && index(menu_info->other_valid, ch)) {
  129.     menu_selected = menu_info->other_response;
  130.     } else {
  131.     X11_nhbell();        /* no match */
  132.     return;
  133.     }
  134.  
  135.     nh_XtPopdown(wp->popup);    /* this removes the event grab */
  136.     exit_x_event = TRUE;    /* exit our event handler */
  137. }
  138.  
  139.  
  140. /* Global functions ======================================================== */
  141.  
  142. void
  143. X11_start_menu(window)
  144.     winid window;
  145. {
  146.     struct xwindow *wp;
  147.     check_winid(window);
  148.  
  149.     wp = &window_list[window];
  150.  
  151.     if (wp->menu_information->is_menu) {
  152.     /* clear old menu and widgets (if any) */
  153.     clear_old_menu(wp);
  154.     } else {
  155.     wp->menu_information->is_menu = TRUE;
  156.     }
  157. }
  158.  
  159. void
  160. X11_add_menu(window, ch, attr, str)
  161.     winid window;
  162.     char ch;
  163.     int attr;
  164.     const char *str;
  165. {
  166.     struct menu_item *item;
  167.     struct menu_info_t *menu_info;
  168.  
  169.     check_winid(window);
  170.     menu_info = window_list[window].menu_information;
  171.     if (!menu_info->is_menu) {
  172.     impossible("add_menu:  called before start_menu");
  173.     return;
  174.     }
  175.  
  176.     item = (struct menu_item *) alloc((unsigned)sizeof(struct menu_item));
  177.     item->next = (struct menu_item *) 0;
  178.     item->selector = ch;
  179.     item->attr = attr;
  180.     item->str = copy_of(str);
  181.  
  182.     if (menu_info->last) {
  183.     menu_info->last->next = item;
  184.     } else {
  185.     menu_info->base = item;
  186.     }
  187.     menu_info->last = item;
  188.     menu_info->count++;
  189. }
  190.  
  191. void
  192. X11_end_menu(window, cancel_ch, cancel_str, morestr)
  193.     winid window;
  194.     char cancel_ch;
  195.     const char *cancel_str;
  196.     const char *morestr;
  197. {
  198.     struct menu_info_t *menu_info;
  199.     check_winid(window);
  200.     menu_info = window_list[window].menu_information;
  201.     if (!menu_info->is_menu) {
  202.     impossible("end_menu:  called before start_menu");
  203.     return;
  204.     }
  205.  
  206.     if(morestr && strlen(morestr))
  207.     X11_add_menu(window, 0, 0, morestr);
  208.     menu_info->other_valid = cancel_str;
  209.     menu_info->other_response = cancel_ch;
  210.     menu_info->query = morestr;
  211. }
  212.  
  213. char
  214. X11_select_menu(window)
  215.     winid window;
  216. {
  217.     struct menu_item *curr;
  218.     struct xwindow *wp;
  219.     struct menu_info_t *menu_info;
  220.     Arg args[8];
  221.     Cardinal num_args;
  222.     String *ptr;
  223.     int i;
  224.     Widget viewport_widget;
  225.     Dimension pixel_height, top_margin, spacing;
  226.     XFontStruct *fs;
  227.  
  228.     check_winid(window);
  229.     wp = &window_list[window];
  230.     menu_info = wp->menu_information;
  231.     if (!menu_info->is_menu) {
  232.     impossible("select_menu:  called before start_menu");
  233.     return '\0';
  234.     }
  235.  
  236. #ifdef VERBOSE
  237.     /* ********** */
  238.     if (menu_info->other_valid) {
  239.     char *cp;
  240.     printf("select_menu: other_valid = \"");
  241.     for (cp = menu_info->other_valid; *cp; cp++) {
  242.         if (*cp < 32) {
  243.         printf("^%c", '@' + *cp);
  244.         } else
  245.         printf("%c", *cp);
  246.     }
  247.     printf("\"\n");
  248.     } else {
  249.     printf("select_menu: other_valid = NULL\n");
  250.     }
  251.     if (menu_info->other_response < 32) {
  252.     printf("select_menu: other_response = '^%c'\n",
  253.                     '@' + menu_info->other_response);
  254.     } else {
  255.     printf("select_menu: other_response = '%c'\n",
  256.                         menu_info->other_response);
  257.     }
  258.     if (menu_info->query) {
  259.     printf("select_menu: query = \"%s\"\n", menu_info->query);
  260.     } else {
  261.     printf("select_menu: query = NULL\n");
  262.     }
  263.     /* ********** */
  264. #endif
  265.  
  266.     num_args = 0;
  267.     XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
  268.  
  269.     wp->popup = XtCreatePopupShell("menu", transientShellWidgetClass,
  270.                    toplevel, args, num_args);
  271.     XtOverrideTranslations(wp->popup,
  272.     XtParseTranslationTable("<Message>WM_PROTOCOLS: menu_delete()"));
  273.  
  274.     menu_info->list_pointer =
  275.     (String *) alloc((unsigned) (sizeof(String) * (menu_info->count+1)));
  276.     for (i = 0, ptr = menu_info->list_pointer, curr = menu_info->base;
  277.             i < menu_info->count; i++, ptr++, curr = curr->next) {
  278.     *ptr = (String) curr->str;
  279.     }
  280.     *ptr = (String) 0;
  281.  
  282.     num_args = 0;
  283.     XtSetArg(args[num_args], XtNallowVert,      True);           num_args++;
  284.  
  285.     viewport_widget = XtCreateManagedWidget(
  286.         "menu_viewport",    /* name */
  287.         viewportWidgetClass,
  288.         wp->popup,        /* parent widget */
  289.         args, num_args);    /* values, and number of values */
  290.  
  291.     num_args = 0;
  292.     XtSetArg(args[num_args], XtNforceColumns, True);        num_args++;
  293.     XtSetArg(args[num_args], XtNdefaultColumns, 1);        num_args++;
  294.     XtSetArg(args[num_args], XtNlist, menu_info->list_pointer);    num_args++;
  295.     XtSetArg(args[num_args], XtNtranslations,
  296.         XtParseTranslationTable(menu_translations));    num_args++;
  297.  
  298.     wp->w = XtCreateManagedWidget(
  299.         "menu_list",        /* name */
  300.         listWidgetClass,
  301.         viewport_widget,    /* parent widget */
  302.         args,            /* set some values */
  303.         num_args);        /* number of values to set */
  304.  
  305.     XtAddCallback(wp->w, XtNcallback, menu_select, (XtPointer) 0);
  306.  
  307.     menu_info->valid_widgets = TRUE;
  308.  
  309.     /* Get the font and margin information. */
  310.     num_args = 0;
  311.     XtSetArg(args[num_args], XtNfont,          &fs);         num_args++;
  312.     XtSetArg(args[num_args], XtNinternalHeight, &top_margin);    num_args++;
  313.     XtSetArg(args[num_args], XtNrowSpacing,     &spacing);    num_args++;
  314.     XtGetValues(wp->w, args, num_args);
  315.  
  316.     /* font height is ascent + descent */
  317.     pixel_height = top_margin +
  318.     ((menu_info->count + 4) *
  319.      (fs->max_bounds.ascent + fs->max_bounds.descent + spacing));
  320.  
  321.     /* if viewport will be bigger than the screen, limit its height */
  322.     if ((Dimension) XtScreen(wp->w)->height <= pixel_height) {
  323.     pixel_height = XtScreen(wp->w)->height / 2;
  324.  
  325.     num_args = 0;
  326.     XtSetArg(args[num_args], XtNheight, pixel_height); num_args++;
  327.     XtSetValues(viewport_widget, args, num_args);
  328.     }
  329.  
  330.     XtRealizeWidget(wp->popup);    /* need to realize before we position */
  331.     positionpopup(wp->popup, FALSE);
  332.  
  333.     menu_selected = '\0';
  334.  
  335.     nh_XtPopup(wp->popup, (int)XtGrabExclusive, wp->w);
  336.     (void) x_event(EXIT_ON_EXIT);
  337.  
  338.     return menu_selected;
  339. }
  340.  
  341. /* End global functions ==================================================== */
  342.  
  343. static char *
  344. copy_of(s)
  345.     const char *s;
  346. {
  347.     char *copy;
  348.     if (s) {
  349.     copy = (char *) alloc((unsigned) (strlen(s)+1));
  350.     Strcpy(copy,s);
  351.     } else {
  352.     copy = (char *) alloc((unsigned) 1);
  353.     *copy = '\0';
  354.     }
  355.  
  356.     return copy;
  357. }
  358.  
  359. static void
  360. clear_old_menu(wp)
  361.     struct xwindow *wp;
  362. {
  363.     struct menu_info_t *menu_info = wp->menu_information;
  364.  
  365.     while (menu_info->base) {
  366.     menu_info->last = menu_info->base;
  367.     menu_info->base = menu_info->base->next;
  368.  
  369.     free(menu_info->last->str);
  370.     free((char *)menu_info->last);
  371.     }
  372.     menu_info->last = (struct menu_item *) 0;
  373.     menu_info->other_valid = (char *) 0;
  374.     menu_info->other_response = '\0';
  375.     menu_info->query = (char *) 0;
  376.     menu_info->count = 0;
  377.  
  378.     if (menu_info->valid_widgets) {
  379.     nh_XtPopdown(wp->popup);
  380.     XtDestroyWidget(wp->popup);
  381.     menu_info->valid_widgets = FALSE;
  382.     free((char *) menu_info->list_pointer);
  383.     }
  384. }
  385.  
  386. void
  387. create_menu_window(wp)
  388.     struct xwindow *wp;
  389. {
  390.     struct menu_info_t *menu_info;
  391.  
  392.     wp->type = NHW_MENU;
  393.  
  394.     wp->menu_information = menu_info = 
  395.             (struct menu_info_t *) alloc(sizeof(struct menu_info_t));
  396.  
  397.     menu_info->base          = (struct menu_item *) 0;
  398.     menu_info->last          = (struct menu_item *) 0;
  399.     menu_info->query          = (char *) 0;
  400.     menu_info->other_valid    = (char *) 0;
  401.     menu_info->other_response = '\0';
  402.     menu_info->count          = 0;
  403.     menu_info->list_pointer   = (String *) 0;
  404.     menu_info->valid_widgets  = FALSE;
  405.     wp->w = wp->popup = (Widget) 0;
  406.     menu_info->is_menu          = FALSE;
  407. }
  408.  
  409. void
  410. destroy_menu_window(wp)
  411.     struct xwindow *wp;
  412. {
  413.     /* printf("destroy_menu_window\n"); */
  414.  
  415.     clear_old_menu(wp);        /* this will also destroy the widgets */
  416.     free((char *) wp->menu_information);
  417.  
  418.     wp->type = NHW_NONE;    /* allow re-use */
  419. }
  420.  
  421.  
  422.